package cn.com.bluemoon.daps.sync.core.sync.sql.ptsql;

import cn.com.bluemoon.daps.common.exception.DapThrowException;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.model.entity.DapDataModelSubordinateKey;
import cn.com.bluemoon.daps.model.entity.DapDataModelTable;
import cn.com.bluemoon.daps.model.entity.DapDataModelTableField;
import cn.com.bluemoon.daps.sync.base.ModifyType;
import cn.com.bluemoon.daps.sync.core.sync.sql.DdlSql;
import cn.com.bluemoon.daps.sync.core.sync.sql.IBmSql;
import cn.com.bluemoon.daps.sync.core.sync.sql.SqlStrBuilder;
import cn.com.bluemoon.daps.sync.core.sync.sql.mysql.MysqlAddColumnDefinition;
import cn.com.bluemoon.daps.sync.core.sync.sql.mysql.MysqlChangeDefinition;
import cn.com.bluemoon.daps.sync.core.sync.sql.mysql.MysqlColumnDefinition;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.CaseInsensitiveMap;

import java.util.Arrays;
import java.util.List;

import static cn.com.bluemoon.daps.model.entity.DapDataModelSubordinateKey.KEY_METHOD_DEFAULT_KEY;

/**
 * 不加反引号
 *
 * @author Jarod.Kong
 **/
@Slf4j
public class MysqlPtSql extends DdlSql implements IBmSql {

    public MysqlPtSql() {
        super.addBlackQuote = false;
    }

    /**
     * 针对非新增的表进行add column
     */
    @Override
    public String createField(DapDataModelTable newT, DapDataModelTableField newF, String preFieldName) {
        MysqlAddColumnDefinition addCol = new MysqlAddColumnDefinition();
        addCol.setPreColumnName(preFieldName);
        MysqlColumnDefinition col = getMysqlColumnDefinition(newF);
        col.setAddBlackQuote(addBlackQuote);
        addCol.setColumnDefinition(col);
        addCol.setAddBlackQuote(addBlackQuote);
        String sql = addCol.toString();
        log.debug("sql=>{}", sql);
        return sql;
    }

    @Override
    public String dropField(DapDataModelTable oldT, DapDataModelTableField oldF) {
        SqlStrBuilder sb = new SqlStrBuilder();
        sb.appendWS("drop column").append(oldF.getFieldName());
        String sql = sb.toString();
        log.debug("sql=>{}", sql);
        return sql;
    }

    @Override
    public String changeField(DapDataModelTable newT, DapDataModelTableField oldF, DapDataModelTableField newF, String preFieldName) {
        MysqlChangeDefinition definition = new MysqlChangeDefinition();
        definition.setOldColName(oldF.getFieldName());
        definition.setAddBlackQuote(addBlackQuote);
        MysqlColumnDefinition col = getMysqlColumnDefinition(newF);
        // 要是新旧字段都是主键，则不需生成primary key 【fixed [2021-06-07 10:18:40] [42000][1068] Multiple primary key defined 针对表中已存在的主键，不可在修改字段时候进行primary key]
        if (isOne(oldF.getPrimaryKey()) && isOne(newF.getPrimaryKey())) {
            col = getMysqlColumnDefinition(newF, ModifyType.ALTER, ModifyType.ModifyLevel.FIELD);
        }
        col.setAddBlackQuote(addBlackQuote);
        definition.setColumnDefinition(col);
        definition.setPreColumnName(preFieldName);
        // CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST | AFTER col_name]
        String sql = definition.toString();
        log.debug("sql=>{}", sql);
        return sql;
    }

    @Override
    public String createIndex(DapDataModelTable newT, DapDataModelSubordinateKey newI) {
        //  | ADD {INDEX | KEY} [index_name]
        //        [index_type] (key_part,...) [index_option] ...
        //  | ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name]
        //        (key_part,...) [index_option] ...
        // index_type:
        //    USING {BTREE | HASH}
        SqlStrBuilder sb = new SqlStrBuilder();
        sb.append(" add ");
        // 排除keytype = 2 的普通索引 ALTER TABLE tablename ADD INDEX 索引的名字 (列名1，列名2,...)
        if (newI.getKeyType() != null && newI.getKeyType() != 1) {
            if (newI.getKeyType() == 4 || newI.getKeyType() == 5) {
                CaseInsensitiveMap<Integer, String> codeAndName = INDEX_TYPE_CONVERTER.getCodeAndName();
                if (codeAndName.containsKey(newI.getKeyType())) {
                    sb.append(codeAndName.get(newI.getKeyType())).append(" ");
                }
                sb.append(" index ");// 可以不加
            } // 唯一索引
            else if (newI.getKeyType() == 3) {// unique有特殊性，要是数据存在非unique则执行报错
                sb.append(" unique ");
            } else {
                sb.append(" index ");
            }
        } else {// normal
            sb.append(" index ");
        }
        sb.append(" ").append(newI.getKeyName()).append(" ");
        String[] fieldNamesSplit = newI.getFieldNamesSplit();
        BmAssetUtils.isTrue(fieldNamesSplit.length > 0, "索引字段列表不可为空");
        List<String> fields = getIndexFieldInfo(newI);
        sb.append("(").append(String.join(",", fields)).append(")");
        // 为空/为1/null/fulltext不生成using btree/hash
        if (newI.getKeyMethod() != null && !KEY_METHOD_DEFAULT_KEY.equals(newI.getKeyMethod()) && newI.getKeyType() != 4) {
            if (INDEX_METHOD_CONVERTER.getCodeAndName().containsKey(newI.getKeyMethod())) {
                sb.append(" using ").append(INDEX_METHOD_CONVERTER.getCodeAndName().get(newI.getKeyMethod()));
            }
        }
        if (newI.getKeyChinName() != null) {
            sb.append(" comment '").append(formatComment(newI.getKeyChinName())).append("' ");
        }
        String sql = sb.toString();
        log.debug("sql=>{}", sql);
        return sql;
    }

    @Override
    public String dropIndex(DapDataModelTable oldT, DapDataModelSubordinateKey oldI) {
        String sql = String.format("drop index %s", oldI.getKeyName());
        log.debug("sql=>{}", sql);
        return sql;
    }

    @Override
    public List<String> changeIndex(DapDataModelTable newT, DapDataModelSubordinateKey oldI, DapDataModelSubordinateKey newI) {
        String sql1 = dropIndex(newT, oldI);
        String sql2 = createIndex(newT, newI);
        if (sql1 != null && sql2 != null) {
            String sql = String.join(", ", Arrays.asList(sql1, sql2));
            log.debug("sql=>{}", sql);
            return Arrays.asList(sql1, sql2);
        }
        throw new DapThrowException("生成修改索引语句失败！");
    }
}
